package com.dm.cloud.utils.mingexcel.medium;

import com.dm.cloud.utils.mingexcel.annotions.CellProperties;
import com.dm.cloud.utils.mingexcel.enums.SameCellMergeEnum;
import com.dm.cloud.utils.mingexcel.worker.SheetWriterFrame;
import org.apache.poi.ss.usermodel.DataFormatter;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.*;

import java.util.*;

public class Merger {
    /**
     * 创建一个合并单元格
     * @param sf
     * @param wb
     * @param sheet
     * @param row 合并单元格所在行
     * @param startRow 合并开始行位置
     * @param endRow 合并结束行位置
     * @param startColumn 合并开始列位置
     * @param endColumn 合并结束列位置
     * @param cellProperties
     * @param value
     */
    public static void createMergeCells(SheetWriterFrame sf, XSSFWorkbook wb, XSSFSheet sheet, XSSFRow row, int startRow, int endRow, int startColumn, int endColumn, CellProperties cellProperties, String value){
        if(endRow>startRow || endColumn>startColumn) {
            //合并单元格
            CellRangeAddress region = new CellRangeAddress(startRow, endRow, startColumn, endColumn);
            sheet.addMergedRegion(region);
            //设置合并单元格边框
            sf.propertiesInitializer.createMergedBorder(sheet,region,cellProperties.border());
        }
        XSSFCell titleCell = row.createCell(startColumn);
        //设置单元样式
        XSSFCellStyle cellStyle = sf.propertiesInitializer.createCellStyle(wb, cellProperties);
        titleCell.setCellStyle(cellStyle);
        titleCell.setCellValue(value);
        return;
    }

    /**
     * 合并指定位置的单元格
     * @param sheet
     * @param startRow
     * @param endRow
     * @param startColumn
     * @param endColumn
     */
    public static void mergeCells(XSSFSheet sheet, int startRow, int endRow, int startColumn, int endColumn){
        if(endRow>startRow || endColumn>startColumn) {
            CellRangeAddress region = new CellRangeAddress(startRow, endRow, startColumn, endColumn);
            sheet.addMergedRegion(region);
        }
        return;
    }

    //计算需要合并的行
    public static void mergeSameCells(XSSFSheet sheet, SameCellMergeEnum scme, int startRow, int allColumns){
        switch(scme){
            case SAME_ROW_MERGE:
                mergeRows(sheet, scme, startRow, allColumns);
                break;
            case SAME_ROW_MERGE_UNDIVIDE_FRONT:
                mergeRows(sheet, scme, startRow, allColumns);
                break;
            default:
                break;
        }
    }

    /**
     * 合并相同行
     * @param sheet
     * @param scme
     * @param startRow
     * @param endRow
     */
    private static void mergeRows(XSSFSheet sheet, SameCellMergeEnum scme, int startRow, int allColumns){
        //用于记录前一列的单元格分割状态
        //List<Integer> 用于记录每列 每个合并单元格的开始行位置 最后一个元素用于记录表格最后一行数据的位置
        DataFormatter formatter = new DataFormatter();
        Map<Integer, List<Integer>> rowDivides = new HashMap<>();
        for (int i = 0; i < allColumns; i++) {
            String currentValue = UUID.randomUUID().toString();
            for (int j = startRow;j<=sheet.getLastRowNum();j++){
                XSSFRow row = sheet.getRow(j);
                String value = formatter.formatCellValue(row.getCell(i));
                //值不同时 记录当前行的位置 表示这是一个新的合并行的开始
                if(!value.equals(currentValue)){
                    int finalJ = j;
                    rowDivides.compute(Integer.valueOf(i),(k, v)->{
                        if(null == v){
                            v = new ArrayList<>();
                        }
                        v.add(finalJ);
                        return v;
                    });
                    currentValue = value;
                }else{
                    if(SameCellMergeEnum.SAME_ROW_MERGE_UNDIVIDE_FRONT == scme){
                        //判断前一列是否做了合并，没做合并的话，后序列也不合并
                        Integer frontColumn = Integer.valueOf(i-1);
                        if(rowDivides.containsKey(frontColumn) && rowDivides.get(frontColumn).contains(Integer.valueOf(j))){
                            int finalJ = j;
                            rowDivides.compute(Integer.valueOf(i),(k, v)->{
                                if(null == v){
                                    v = new ArrayList<>();
                                }
                                v.add(finalJ);
                                return v;
                            });
                        }
                    }
                }
            }

            //最后需要添加一个最尾行 因为列表中的行数代表新单元格的开始行位置，所以最尾行+1代表下一个单元格的开始位置
            //实际上最后一个只做尾部处理，并不会生成新的单元格
            rowDivides.compute(Integer.valueOf(i),(k, v)->{
                if(null == v){
                    v = new ArrayList<>();
                }
                v.add(sheet.getLastRowNum()+1);
                return v;
            });
        }

        //最后做合并处理
        if(rowDivides.size()>0){
            rowDivides.entrySet().stream().forEach(
                    entry->{
                        int column = entry.getKey();
                        List<Integer> rows = entry.getValue();
                        //最后一个用于包底 两个元素确认一个合并单元格 第一个元素是开始行位置 第二个元素的前一行是结束行位置
                        for (int i = 0; i < rows.size() -1 ; i++) {
                            Merger.mergeCells(sheet,rows.get(i),rows.get(i+1) - 1,column,column);
                        }
                    }
            );
        }
    }
}
